package com.unknowpupil.cloud.consumer.oauth.controller;

import com.google.common.collect.Maps;
import com.unknowpupil.ccommon.utils.GsonUtils;
import com.unknowpupil.cloud.common.dto.ResponseResult;
import com.unknowpupil.ccommon.utils.JsonUtils;
import com.unknowpupil.ccommon.utils.OkHttpClientUtil;
import com.unknowpupil.cloud.consumer.oauth.dto.LoginInfo;
import com.unknowpupil.cloud.consumer.oauth.dto.LoginParam;
import com.unknowpupil.cloud.provider.account.domain.UnAccount;
import com.unknowpupil.cloud.consumer.profile.feign.ProfileFeign;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;

/**
 * 登陆管理
 *
 * @Classname: LoginController
 * @Author: <a> w10g </a>
 * @CreateDate: Create in 2020/1/4 4:11
 * @Description:
 * @Version: 1.0
 */
//@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@Slf4j
public class LoginController {
    private static final String URL_OAUTH_TOKEN = "http://localhost:8092/oauth/token";
    @Value("${consumer.oauth2.grant_type}")
    private String oauth2GrantType;
    @Value("${consumer.oauth2.client_id}")
    private String oauth2ClientId;
    @Value("${consumer.oauth2.client_secret}")
    private String oauth2ClientSecret;

    @Resource(name = "userDetailsServiceBean")
    private UserDetailsService userDetailsService;
    @Resource
    private BCryptPasswordEncoder passwordEncoder;
    @Resource
    private TokenStore tokenStore;
    /**
     * 用feign 来请求
     */
    @Resource
    private ProfileFeign profileFeign;

    @PostMapping(value = "/user/login")
    public ResponseResult<Map<String, Object>> login(@RequestBody LoginParam loginParam) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(loginParam.getUsername());
        if (userDetails == null || !passwordEncoder.matches(loginParam.getPassword(), userDetails.getPassword())) {
            log.info("[用户模块] 登陆失败，账号={}\n 密码={}\n 失败原因=账号或者密码错误",loginParam.getUsername(),loginParam.getPassword());
            return new ResponseResult<Map<String, Object>>(ResponseResult.CodeStatus.FAIL, "账号或者密码错误");
        }
        Map<String, Object> result = Maps.newHashMap();
        Map<String, String> param = Maps.newHashMap();
        param.put("username", loginParam.getUsername());
        param.put("password", loginParam.getPassword());
        param.put("grant_type", oauth2GrantType);
        param.put("client_id", oauth2ClientId);
        param.put("client_secret", oauth2ClientSecret);
        try {
            Response response = (Response) OkHttpClientUtil.getInstance().postData(URL_OAUTH_TOKEN, param);
            String jsonString = Objects.requireNonNull(response.body()).string();
            Map<String, Object> jsonMap = JsonUtils.json2map(jsonString);
            result.put("token", String.valueOf(jsonMap.get("access_token")));
            log.info("[用户模块] 登陆成功，账号={}，密码={}，结果={}",loginParam.getUsername(),loginParam.getPassword(),GsonUtils.toJson(jsonString));

        } catch (Exception e) {
            log.info("[用户模块] 登陆失败，账号={}\n 密码={}\n 失败原因={}",loginParam.getUsername(),loginParam.getPassword(),GsonUtils.toJson(e));

            e.printStackTrace();
        }
        return new ResponseResult<Map<String, Object>>(ResponseResult.CodeStatus.OK, "登陆成功", result);
    }
    /**
     * 功能描述: <br>
     * 〈 获取用户信息，注意这里  这里拿用户信息，下面项目有一个提供dubbo服务的的provider 也就是说可以之间在这里 注入 用户服务来取用户信息
     *   这里没有授权的问题，
     *   也不排除 后面的服务需要用到 feign来请求 springcloud 服务 用feign怎么待token请求呢？ 这里就用feign来演示一下
     * 〉
     *
     * @param: request
     * @since: 1.0.0
     * @auther: w10g
     * @return:
     * @Date: 2020/1/4 14:35
     */
    @GetMapping(value = "/user/info")
    public ResponseResult<LoginInfo> info(HttpServletRequest request) throws Exception {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //这个通讯请求有些毛病 这里请求user/info需要待token feign是取转发到springcloud 服务之上
        //那么对于feign来说并不会把你得token信息请求参数请求头一并带你转发到你得目标服务器 所有
        //需要堆feign做单独得配置 feign拦截器 请求feign的时候 把头体封装一下 那么有一个feign拦截模块
        //fegin 拦截器封装完了，在这 配置在controller里请求到feign的方式 需要改个东西 三种方式默认java自带url 一个是okhttp 一个是httpclient
        log.info("[用户模块] 使用SpringCloud Feign http restful 风格访问");
        String jsonStr = profileFeign.info(authentication.getName());
        UnAccount account = JsonUtils.json2pojoByTree(jsonStr,"data",UnAccount.class);
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setName(account.getUserName());
        loginInfo.setAvatar(account.getIcon());
        log.info("[用户模块] 获取用户信息成功，用户={}", GsonUtils.toJson(loginInfo));
        return new ResponseResult<>(ResponseResult.CodeStatus.OK, "获取用户信息", loginInfo);
    }

    @PostMapping(value = "/user/logout")
    public ResponseResult<Void> logout(HttpServletRequest request){
        String access_token = request.getParameter("access_token");

        //token在tokenStore种
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(access_token);

        tokenStore.removeAccessToken(oAuth2AccessToken);
        log.info("[用户模块] 注销成功 token={}",access_token);
        return new ResponseResult<>(ResponseResult.CodeStatus.OK, "用户注销", null);

    }
}
